package it.traveldreamWeb.customer;

import it.traveldream.beans.BookingManagerInterface;
import it.traveldream.beans.PackageManagerInterface;
import it.traveldream.dto.HotelDTO.HotelRoomType;
import it.traveldream.dto.TPDTO;
import it.traveldream.dto.TransportMeanDTO;
import it.traveldream.exceptions.TPNotFoundException;
import it.traveldreamWeb.shared.HotelRoom;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

@ManagedBean(name="packageViewBean")
@ViewScoped
public class PackageViewBean {

	@EJB
	private PackageManagerInterface packageManager;
	@EJB
	private BookingManagerInterface bookingManager;

	private TransportMeanDTO selectedMean;
	private Long TPId;
	private TPDTO selectedTP;

	private int searchDuring;
	private Date searchSince;
	private int duration;
	private int travellers;

	private boolean isAvailable;
	private List<Date> disabledDates;
	private List<TransportMeanDTO> availableMeans = new ArrayList<>();
	private Date leavingDate;
	private List<HotelRoom> selectedRooms = new ArrayList<>();

	@ManagedProperty(value="#{reservationBean}")
	private ReservationBean session;

	private String error;

	public void init() {
		// clean session
		this.session.setSelectedHotel(null);
		this.session.setSelectedExs(null);
		this.session.setSelectedRooms(null);
		
		if (this.TPId == null){
			ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
			try {
				String path = context.getRequestContextPath()+context.getRequestServletPath();
				context.redirect(path.replace("PackageView.xhtml", "PackageList.xhtml"));
			} catch (IOException e) {
				throw new RuntimeException();
			}
		} else {
			this.selectedTP = new TPDTO();
			try {
				this.selectedTP.setTPId(this.TPId);
				this.selectedTP = this.packageManager.getTP(this.selectedTP);
				
				// inizializzo le stanze a 0
				for (Map.Entry<HotelRoomType, Integer> e : this.selectedTP.getHotel().getRooms().entrySet()){
					HotelRoom r = new HotelRoom();
					r.setType(e.getKey());
					r.setTotalRooms(this.selectedTP.getHotel().getRooms().get(e.getKey()));
					r.setPrice(this.selectedTP.getHotel().getPrices().get(e.getKey()));
					r.setSelectedRooms(0);
					this.selectedRooms.add(r);
				}

				// recupero i mezzi e inizializzo con quello compreso nel pacchetto
				this.selectedMean = this.selectedTP.getMean();
				this.availableMeans = new ArrayList<>(this.packageManager.getAlternativeMeans(this.selectedTP));

				ArrayList<TransportMeanDTO> allMeans = new ArrayList<>(this.availableMeans);
				allMeans.add(this.selectedMean);
				MeanConverter.init(allMeans);
				
				// recupero eventuali sessioni
				if (this.session.getSelectedMean() != null)
					this.selectedMean = this.session.getSelectedMean();
				if (this.session.getTravellers() > 0)
					this.travellers = this.session.getTravellers();
				if (this.session.getLeavingDate() != null)
					this.searchSince = this.session.getLeavingDate();
				if (this.session.getDuration() > 0)
					this.duration = this.session.getDuration();
			} catch (TPNotFoundException e) {
				this.setError("Invalid request. Please go back and try again");
			}
		}

	}

	public ReservationBean getSession() {
		return this.session;
	}

	public void setSession(ReservationBean session) {
		this.session = session;
	}

	public Long getTPId() {
		return this.TPId;
	}

	public void setTPId(Long tPId) {
		this.TPId = tPId;
	}

	public String getError() {
		return this.error;
	}

	public void setError(String error) {
		this.error = error;
	}
	
	public List<HotelRoom> getSelectedRooms() {
	    return this.selectedRooms;
	}
	
	public void setSelectedRooms(List<HotelRoom> r) {
	    this.selectedRooms = r;
	}

	public TransportMeanDTO getSelectedMean() {
		return this.selectedMean;
	}

	public void setSelectedMean(TransportMeanDTO selectedMean) {
		this.selectedMean = selectedMean;
	}
	
	public TPDTO getSelectedTP() {
		return this.selectedTP;
	}

	public void setSelectedTP(TPDTO selectedTP) {
		this.selectedTP = selectedTP;
	}

	public Date getToday(){
		return Calendar.getInstance().getTime();
	}

	public int getSearchDuring() {
		return this.searchDuring;
	}

	public void setSearchDuring(int searchDuring) {
		this.searchDuring = searchDuring;
	}

	public Date getSearchSince() {
		return this.searchSince;
	}

	public void setSearchSince(Date searchSince) {
		this.searchSince = searchSince;
	}

	public List<TransportMeanDTO> getAvailableMeans() {
		return this.availableMeans;
	}

	public void setAvailableMeans(List<TransportMeanDTO> availableMeans) {
		this.availableMeans = availableMeans;
	}

	public int getTravellers() {
		return this.travellers;
	}

	public void setTravellers(int travellers) {
		this.travellers = travellers;
	}

	public int getDuration() {
		return this.duration;
	}

	public void setDuration(int duration) {
		this.duration = duration;
	}

	public boolean getIsAvailable() {
		return this.isAvailable;
	}

	public void setIsAvailable(boolean isAvailable) {
		this.isAvailable = isAvailable;
	}

	public String getDisabledDates() {
		StringBuilder sb = new StringBuilder("");
		
		if (this.disabledDates != null){
			DateFormat df = new SimpleDateFormat("M-dd-yyyy");
		
			for (Date d : this.disabledDates){
				sb.append("'");
				sb.append(df.format(d));
				sb.append("'");
				sb.append(",");
			}
			if (sb.length() > 0)
				sb.deleteCharAt(sb.length()-1);
		}
		return sb.toString();
	}

	public Date getLeavingDate() {
		return this.leavingDate;
	}

	public void setLeavingDate(Date leavingDate) {
		this.leavingDate = leavingDate;
	}

	public boolean validateData(){
		if (this.travellers <= 0){
			this.setError("Please, enter the number of travellers first");
			return false;
		}
		if (this.duration <= 0){
			this.setError("Please, enter the travel duration first");
			return false;
		}
		if (this.searchSince == null){
			this.setError("Please, choose a leaving date first");
			return false;
		}
		if (this.searchDuring < 0){
			this.setError("Please, enter a valid search range");
			return false;
		}
		return true;
	}
	
	public void checkAvailability(){
		this.setError("");
		this.isAvailable = false;
		try{
			if (! this.validateData())
				return;
			Calendar cal = Calendar.getInstance();
			cal.setTime(this.searchSince);
			cal.add(Calendar.DATE, this.searchDuring);
			List<Date> availableDates = this.bookingManager.getAvailableLeavingDates(this.selectedMean, 
					this.searchSince, cal.getTime(), this.duration, this.travellers);

			if (availableDates.size() == 0){
				this.setError("Sorry, transport mean is sold out in chosen period");
				return;
			}

			this.session.setSelectedMean(this.selectedMean);
			this.session.setTravellers(this.travellers);
			this.session.setLeavingDate(this.leavingDate);
			this.session.setDuration(this.duration);
			this.isAvailable = true;
			this.leavingDate = this.searchSince;
			this.disabledDates = new ArrayList<>();
			cal.setTime(this.searchSince);
			for (int i = 0;i < this.searchDuring;i++){
				cal.add(Calendar.DATE, (i==0) ? i : 1);
				if (! availableDates.contains(cal.getTime()))
					this.disabledDates.add(cal.getTime());
			}
		} catch (Exception e){
			this.setError("Internal error! Please try again");
		}
	}
	
	public String customize(){
		this.setError("");
		try{
			if (! this.validateData())
				return null;
			if (this.leavingDate == null){
				this.setError("Please, choose a valid leaving date first");
				return null;
			}
			
			this.session.setSelectedMean(this.selectedMean);
			this.session.setTravellers(this.travellers);
			this.session.setLeavingDate(this.leavingDate);
			this.session.setDuration(this.duration);
			return "PackageCustomization?faces-redirect=true&includeViewParams=true";
		} catch (Exception e){
			this.setError("Internal error! Please try again");
			return null;
		}
	}
	
	public String proceed(){
		
		this.setError("");
		try{
			if (! this.validateData())
				return "";
			if (this.leavingDate == null){
				this.setError("Please, choose a valid leaving date first");
				return "";
			}
			boolean someRoom = false;
			for (HotelRoom h : this.selectedRooms)
				if (h.getSelectedRooms() != null && h.getSelectedRooms() > 0){
					someRoom = true;
					break;
				}	
			if (! someRoom){
				this.setError("Please, choose some room first");
				return "";
			}
				
			this.session.setSelectedMean(this.selectedMean);
			this.session.setSelectedHotel(this.selectedTP.getHotel());
			this.session.setSelectedExs(this.selectedTP.getExcursions());
			this.session.setSelectedRooms(this.selectedRooms);
			this.session.setTravellers(this.travellers);
			this.session.setLeavingDate(this.leavingDate);
			this.session.setDuration(this.duration);
			return "ReservationSummary?faces-redirect=true";
		} catch (Exception e){
			this.setError("Internal error! Please try again");
			return "";
		}
	}
}
